package
{
	import as3isolib.core.IIsoDisplayObject;
	import as3isolib.display.primitive.IsoBox;
	import as3isolib.geom.Pt;
	
	import flash.geom.Vector3D;

	public class Citizen implements ISimObject, IPathingObject, ISerializable
	{
		public static const SIZE:Number = .3;
		public static const SPEED:Number = 3;
		public var location:Pt = new Pt();
		public var isoDisplay:IIsoDisplayObject;
		public var waypointDisplay:IIsoDisplayObject;
		
		private var m_nextDestination:Vector3D;
		private var m_lastDestination:Vector3D;
		
		private var m_lastDirection:Vector3D;
		private var m_nextDirection:Vector3D;
		
		private var m_waypointDirty:Boolean = false;
		private var m_currentLocation:Vector3D;
		private var m_nextLocation:Vector3D;
		
		private var m_destinationStrategy:Function;
		
		// How many stores will this person shop at, ie how wealthy he is
		public var wealthFactor:int = 100;
		
		
		public function Citizen()
		{
			m_destinationStrategy = setupRandomNextDestination;
			m_nextLocation = new Vector3D(0,0,0);
			m_currentLocation = m_nextLocation;
			this.isoDisplay = new IsoBox();
			this.isoDisplay.setSize(SIZE*Constants.SQUARE_SIZE, SIZE*Constants.SQUARE_SIZE,3*SIZE*Constants.SQUARE_SIZE);
			this.waypointDisplay = new IsoBox();
			this.waypointDisplay.setSize(SIZE*.5*Constants.SQUARE_SIZE, SIZE*Constants.SQUARE_SIZE*.5,.5*3*SIZE*Constants.SQUARE_SIZE);
			this.waypointDisplay.container.visible = false;
			setupNextDestination();
		}
		
		public function serialize():Object{
			var serData:Object = new Object();
			serData.locationX = location.x;
			serData.locationY = location.y;
			serData.locationZ = location.z;
			return serData;
		}
		
		public function wakeup(serData:Object):void{
			
		}
		
		public function updateCurrentState():void{
			m_currentLocation = m_nextLocation;
			isoDisplay.x = m_nextLocation.x;
			isoDisplay.y = m_nextLocation.y;
			isoDisplay.z = m_nextLocation.z;
			
			if(m_waypointDirty){
				m_waypointDirty = false;
				this.waypointDisplay.x = m_nextDestination.x;
				this.waypointDisplay.y = m_nextDestination.y;
				this.waypointDisplay.z = m_nextDestination.z;
			}
			
			m_lastDestination = m_nextDestination;
		}
		
		public function setupNextState(delta:int):void{
			if(hasReachedNextDestination(delta)){
				setupNextDestination();
			} else {
				moveTowardsNextDestination(delta);
			}
			
			m_lastDirection = m_nextDirection;
		}
		
		public function setNextDestination(dest:Vector3D):void{
			m_nextDestination = dest;
		}
		
		public function getLastDestination():Vector3D{
			return m_lastDestination;
		}
		
		public function getCurrentLocation():Vector3D{
			return m_currentLocation;
		}
		
		private function getDirectionFromDestination():Vector3D{
			var direction:Vector3D = m_nextDestination.subtract(new Vector3D(isoDisplay.x, isoDisplay.y, isoDisplay.z));
			direction.normalize();
			return direction;
		}
		
		private function distanceFromDestination():Number{
			return m_nextDestination.subtract(new Vector3D(isoDisplay.x, isoDisplay.y, isoDisplay.z)).length;	
		}
		
		private function hasReachedNextDestination(delta:int):Boolean{
			if(getDirectionFromDestination().dotProduct(m_lastDirection) <= 0){
				return true;
			} else {
				return false;
			}
		}
		
		public function switchToPathingDestinationStrategy():void{
			m_destinationStrategy = setupPathingNextDestination;
		}
		
		private function setupPathingNextDestination():void{
			m_nextDestination = Global.pathManager.getNextDestination(this);
		}
		
		private function setupRandomNextDestination():void{
			m_nextDestination = new Vector3D(Math.random()*20*Constants.SQUARE_SIZE, Math.random()*20*Constants.SQUARE_SIZE, 0);
		}
		
		private function setupNextDestination():void{
			this.m_destinationStrategy();
			m_nextDirection = m_nextDestination.subtract(new Vector3D(m_currentLocation.x, m_currentLocation.y, m_currentLocation.z));
			m_nextDirection.normalize();
			m_lastDirection = m_nextDirection.clone();
			m_waypointDirty = true;
		}
		
		private function moveTowardsNextDestination(delta:int):void{
			var speed:Number = delta*SPEED/100;
			m_nextDirection = getDirectionFromDestination();
			m_nextLocation = m_nextLocation.add(new Vector3D(m_nextDirection.x*speed, m_nextDirection.y*speed, 0));
			if(m_nextLocation.subtract(m_currentLocation).length >= distanceFromDestination()){
				m_nextLocation = m_nextDestination;
				setupNextDestination();
			}
		}
		
		public static function serializeVector(citizens:Vector.<Citizen>):Array{
			var i:int, length:int = citizens.length;
			var serialized:Array = new Array();
			for(i = 0; i < length; i++){
				serialized.push(citizens[i].serialize());
			}
			return serialized;
		}
		
		public static function unserializeVector(serDatas:Array, citizens:Vector.<Citizen>):void{
			var i:int, l:int = serDatas.length;
			for(i = 0; i < length; i++){
				var citizen:Citizen = new Citizen();
				citizen.wakeup(serDatas[i]);
				citizens.push(citizen);
			}
		}
	}
}